package pl.bizuteria.sklep.admin.client.activity.product;

import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import pl.bizuteria.sklep.admin.client.place.ProxyCreatePlace;
import pl.bizuteria.sklep.admin.client.place.ProxyEditPlace;
import pl.bizuteria.sklep.admin.client.ui.product.IProxyListView;
import pl.bizuteria.sklep.api.shared.request.ApplicationRequestFactory;

import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.cellview.client.AbstractHasData;
import com.google.gwt.user.cellview.client.ColumnSortList;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.CellPreviewEvent;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.DefaultSelectionEventManager.EventTranslator;
import com.google.gwt.view.client.DefaultSelectionEventManager.SelectAction;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.Range;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;

public abstract class AbstractProxyListActivity<P extends EntityProxy> extends
		AbstractActivity implements IProxyListView.Delegate {

	protected abstract Logger logger();

	protected IProxyListView<P> view;
	protected PlaceController placeController;
	protected Class<P> proxyClass;
	protected final ApplicationRequestFactory requestFactory;
	private MultiSelectionModel<P> multiSelectionModel;
	private SingleSelectionModel<P> singleSelectionModel;
	private AsyncDataProvider<P> asyncDataProvider;

	public AbstractProxyListActivity(IProxyListView<P> view,
			PlaceController placeController, Class<P> proxyClass,
			ApplicationRequestFactory requestFactory) {
		super();
		this.view = view;
		this.placeController = placeController;
		this.proxyClass = proxyClass;
		this.requestFactory = requestFactory;

		final AbstractHasData<P> hasData = view.asHasData();

		addSelectionListener(hasData);
		addDataProvider(hasData);

	}

	@Override
	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		panel.setWidget(view);
		view.setDelegate(this);

	}

	private void addSelectionListener(AbstractHasData<P> hasData) {
		addMultiSelection(hasData);
		// addSingleSelection(hasData);
	}

	private void addSingleSelection(AbstractHasData<P> hasData) {
		singleSelectionModel = new SingleSelectionModel<P>();

		singleSelectionModel.addSelectionChangeHandler(new Handler() {

			@Override
			public void onSelectionChange(SelectionChangeEvent event) {
				editObject(singleSelectionModel.getSelectedObject());
				System.out.println("XXX");
				System.out.println("onSelectionChange   " + event);
			}
		});

		hasData.setSelectionModel(singleSelectionModel,
				DefaultSelectionEventManager.<P> createBlacklistManager(0));
	}

	private void addMultiSelection(AbstractHasData<P> hasData) {
		multiSelectionModel = new MultiSelectionModel<P>();

		EventTranslator<P> translator = new DefaultSelectionEventManager.CheckboxEventTranslator<P>() {
			@Override
			public SelectAction translateSelectionEvent(
					CellPreviewEvent<P> event) {
				// System.out.println("tranlate");
				// if nie click on checkbox wtedy select, ani na pole w ktorym
				// jest checkbox
				SelectAction action = super.translateSelectionEvent(event);
				// System.out.println("Action = " + action + " event = " +
				// event.getNativeEvent().getType());
				if (action.equals(SelectAction.IGNORE)
						&& event.getColumn() != 0) {
					P selectedObject = event.getValue();
					if (selectedObject != null) {
						editObject(selectedObject);
					}
					return SelectAction.IGNORE;
				}

				return super.translateSelectionEvent(event);
			}
		};

		hasData.setSelectionModel(multiSelectionModel,
				DefaultSelectionEventManager
						.<P> createCustomManager(translator));
		// hasData.setSelectionModel(multiSelectionModel);

	}

	protected void editObject(P selectedObject) {
		placeController.goTo(new ProxyEditPlace(selectedObject.stableId()));
	}

	private void addDataProvider(HasData<P> hasData) {
		asyncDataProvider = new AsyncDataProvider<P>() {

			@Override
			protected void onRangeChanged(final HasData<P> display) {
				final Range visibleRange = display.getVisibleRange();
				logger().info("onRangeChanged VisibleRange = " + visibleRange);

				Receiver<? super List<P>> receiver = new Receiver<List<P>>() {
					@Override
					public void onSuccess(List<P> response) {
						logger().info(
								"Received new row data  " + response
										+ " visibleRange = " + visibleRange);
						display.setRowData(visibleRange.getStart(), response);
					}
				};
				ColumnSortList columnSortList = view.getColumnSortList();
				if (columnSortList != null
						&& view.getColumnSortList().size() > 0) {
					// trzeba to zamienic na dane do sortowania po stronie
					// serwera...
					// System.out.println("Nie null " +
					// columnSortList.get(0).getColumn());
				}

				createFindRequest(visibleRange).fire(receiver);

				Receiver<Integer> countReceiver = new Receiver<Integer>() {

					@Override
					public void onSuccess(Integer response) {
						logger().info("Received new count data  " + response);
						display.setRowCount(response, true);
					}
				};
				createCountRequest().fire(countReceiver);
			}

		};

		// w tym momencie sa juz ladowane dane!! wiec trzeba uwazac
		asyncDataProvider.addDataDisplay(hasData);
	}

	protected abstract Request<List<P>> createFindRequest(Range range);

	protected abstract Request<Void> createDeleteRequest(Set<P> elements);

	protected abstract Request<Integer> createCountRequest();

	@Override
	public void createClicked() {
		placeController.goTo(new ProxyCreatePlace(proxyClass));
	}

	@Override
	public void deleteClicked() {

		// List<P> displayedItems = view.asHasData().getDisplayedItems();
		// P item1 = displayedItems.get(1);

		// boolean flaga = !multiSelectionModel.isSelected(item1);
		// System.out.println("Setting object number 1 na + " + flaga);
		// multiSelectionModel.setSelected(item1, flaga);

		// Window.alert("tutaj jakis msg\n Uwaga czy na pewno?");
		Set<P> selectedSet = multiSelectionModel.getSelectedSet();
		String log = "deleting: " + "\n";
		for (P e : selectedSet) {
			log += e.stableId() + "\n";
		}

		// Window.alert(log);
		logger().info("Delete Clicked, SelectedSet = " + selectedSet);
		logger().info(log);
		createDeleteRequest(selectedSet).fire(new Receiver<Void>() {

			@Override
			public void onSuccess(Void response) {
				// Window.alert("Mass delete success, a proxy class = " +
				// proxyClass);
				Range visibleRange = view.asHasData().getVisibleRange();
				logger().info(
						"Remove Success, reloding data, visibleRange = "
								+ visibleRange);
				view.asHasData()
						.setVisibleRangeAndClearData(visibleRange, true);
				// to chyba nie potrzebne bo i tak lista zostaje na ekranie,
				// tylko trzeba ja przeladowac
				// placeController.goTo(new ProxyListPlace(proxyClass));
			}
		});
	}

	@Override
	public void onStop() {
		asyncDataProvider.removeDataDisplay(view.asHasData());
		view = null;
	}

}
